<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="Cnuy6" id="Cnuy6"><span data-lake-id="ub08c15ea" id="ub08c15ea" style="color: rgba(25, 26, 31, 0.9)">典型回答</span></h1>
  <p data-lake-id="u4ca9ba9e" id="u4ca9ba9e"><br></p>
  <p data-lake-id="u0a655c05" id="u0a655c05"><span data-lake-id="u2dc217b2" id="u2dc217b2">当我们使用Redis作为存储时，如果发生一些特殊情况，比如明星官宣的突发事件，世界杯等重大活动，双十一的活动秒杀等等，就会出现特别大的流量，并且会导致某些热词、商品等被频繁的查询和访问。</span></p>
  <p data-lake-id="u2d9615ad" id="u2d9615ad"><span data-lake-id="ue72e3ebc" id="ue72e3ebc">​</span><br></p>
  <p data-lake-id="u32d0efb6" id="u32d0efb6"><strong><span data-lake-id="ua0e91ce0" id="ua0e91ce0">如果在同一个时间点上，Redis中的同一个key被大量访问，就会导致流量过于集中，使得很多物理资源无法支撑，如网络带宽、物理存储空间、数据库连接等。</span></strong></p>
  <p data-lake-id="ud17d5dec" id="ud17d5dec"><span data-lake-id="uf8b4311b" id="uf8b4311b">​</span><br></p>
  <p data-lake-id="uad39ae34" id="uad39ae34"><span data-lake-id="u5dd7d3d2" id="u5dd7d3d2">这也是为什么某某明星官宣之后，微博上面就会出现宕机的情况。有时候这种宕机发生后，其他功能都是可以使用的，只是和这个热点有关的内容会无法访问，这其实就和热点数据有关系了。</span></p>
  <p data-lake-id="u7a4d0f56" id="u7a4d0f56" style="text-align: justify"><span data-lake-id="u1ca34c42" id="u1ca34c42" class="lake-fontsize-12" style="color: rgb(85, 85, 85)">​</span><br></p>
  <p data-lake-id="uac80ff15" id="uac80ff15" style="text-align: justify"><strong><span data-lake-id="uf6acc977" id="uf6acc977">对于热key的处理，主要在于事前预测和事中解决。</span></strong></p>
  <p data-lake-id="uc2b7bffd" id="uc2b7bffd" style="text-align: justify"><br></p>
  <p data-lake-id="u273da449" id="u273da449" style="text-align: justify"><span data-lake-id="u547d5692" id="u547d5692">对于事前预测就是根据一些根据经验，提前的识别出可能成为热key的Key，比如大促秒杀活动等。</span></p>
  <p data-lake-id="u345e7ea9" id="u345e7ea9" style="text-align: justify"><span data-lake-id="u42021a98" id="u42021a98">​</span><br></p>
  <p data-lake-id="u08ca064a" id="u08ca064a" style="text-align: justify"><strong><span data-lake-id="u2d26d473" id="u2d26d473">在事中解决方面，主要可以考虑，热点key拆分、多级缓存、热key备份、限流等方案来解决。</span></strong></p>
  <p data-lake-id="ue6048ae6" id="ue6048ae6" style="text-align: justify"><span data-lake-id="u0a5526b6" id="u0a5526b6">​</span><br></p>
  <h1 data-lake-id="VqSKn" id="VqSKn"><span data-lake-id="u42c257cd" id="u42c257cd" style="color: rgb(85, 85, 85)">扩展知识</span></h1>
  <p data-lake-id="u46b0f486" id="u46b0f486"><br></p>
  <h2 data-lake-id="jnf9Y" id="jnf9Y"><span data-lake-id="u8036b3d9" id="u8036b3d9">多热算热，给个标准？</span></h2>
  <p data-lake-id="ue12ddd60" id="ue12ddd60"><br></p>
  <p data-lake-id="ua2c5a3ab" id="ua2c5a3ab"><span data-lake-id="u7d5f8a9d" id="u7d5f8a9d">到底"多热算热"，这个其实需要根据实际的业务情况以及你自己的缓存服务器的整体存储情况而定的。</span></p>
  <p data-lake-id="ucd633d8e" id="ucd633d8e"><span data-lake-id="u20af8769" id="u20af8769">​</span><br></p>
  <p data-lake-id="udf430bf7" id="udf430bf7"><span data-lake-id="ubf175a50" id="ubf175a50">JD有一个框架叫做hotkey，他就是专门做热key检测的，他的热key定义是在单位时间内访问超过设定的阈值频次就是热key，这个阈值需要业务自己设定，并不断的调整和优化。</span></p>
  <p data-lake-id="udb04d0e2" id="udb04d0e2"><span data-lake-id="u97c260bf" id="u97c260bf">​</span><br></p>
  <p data-lake-id="u3d784ac4" id="u3d784ac4"><span data-lake-id="u0883890b" id="u0883890b">热key的定义，通常以其接收到的Key被请求频率来判定，例如：</span></p>
  <ul list="u29483c91">
   <li fid="u04f27901" data-lake-id="u9936a6a6" id="u9936a6a6" data-lake-index-type="true"><span data-lake-id="ud53deba5" id="ud53deba5">QPS集中在特定的Key：Redis实例的总QPS为10,000，而其中一个Key的每秒访问量达到了7,000。那么这个key就算热key了。</span></li>
   <li fid="u04f27901" data-lake-id="uc11cc734" id="uc11cc734" data-lake-index-type="true"><span data-lake-id="uf452bc57" id="uf452bc57">带宽使用率集中在特定的Key：对一个拥有1000个成员且总大小为1 MB的HASH Key每秒发送大量的HGETALL操作请求。</span></li>
   <li fid="u04f27901" data-lake-id="uac3e3227" id="uac3e3227" data-lake-index-type="true"><span data-lake-id="u2ce5ee26" id="u2ce5ee26">CPU使用时间占比集中在特定的Key：对一个拥有10000个成员的Key（ZSET类型）每秒发送大量的ZRANGE操作请求。</span></li>
  </ul>
  <p data-lake-id="u757972d9" id="u757972d9"><span data-lake-id="u055bcd18" id="u055bcd18">​</span><br></p>
  <h2 data-lake-id="brGyw" id="brGyw"><span data-lake-id="u603f8f0b" id="u603f8f0b">识别热Key</span></h2>
  <p data-lake-id="uc4722c28" id="uc4722c28"><span data-lake-id="u07ff6c61" id="u07ff6c61">想要解决热key的问题，首先要想办法识别出哪些key是热key。主要由以下几个方案：</span></p>
  <h3 data-lake-id="cXeLN" id="cXeLN"><span data-lake-id="uec95676b" id="uec95676b">根据经验，提前预测</span></h3>
  <p data-lake-id="u072db064" id="u072db064"><br></p>
  <p data-lake-id="u02c730be" id="u02c730be"><span data-lake-id="u6f37b0f5" id="u6f37b0f5">这种方法在大多数情况下还是比较奏效的。比较常见的就是电商系统中，会在做秒杀、抢购等业务开始前就能预测出热key。</span></p>
  <p data-lake-id="ud8cf006b" id="ud8cf006b"><span data-lake-id="ubbeb991b" id="ubbeb991b">​</span><br></p>
  <p data-lake-id="u3fa408c3" id="u3fa408c3"><span data-lake-id="u305265c0" id="u305265c0">但是，这种方式的局限性也很大，就是有些热key是完全没办法预测的，比如明星什么时候要官宣这种事情就无法预测。</span></p>
  <p data-lake-id="u84c4d44f" id="u84c4d44f"><span data-lake-id="u550d7ae7" id="u550d7ae7">​</span><br></p>
  <h3 data-lake-id="ibN33" id="ibN33"><span data-lake-id="uae6b4991" id="uae6b4991">实时收集</span></h3>
  <p data-lake-id="u6dd04a3f" id="u6dd04a3f"><br></p>
  <p data-lake-id="u632a0f3a" id="u632a0f3a"><span data-lake-id="ue92b144d" id="ue92b144d">还有一种热点数据的发现机制，那就是实时的做收集，比如在客户端、服务端或者在代理层，都可以对实时数据进行采集，然后进行统计汇总。</span></p>
  <p data-lake-id="u49e536ef" id="u49e536ef"><span data-lake-id="u16e38499" id="u16e38499">​</span><br></p>
  <p data-lake-id="u536fa1ae" id="u536fa1ae"><span data-lake-id="uf52b8315" id="uf52b8315">达到一定的数量之后，就会被识别为热key。</span></p>
  <p data-lake-id="u13daedd9" id="u13daedd9"><span data-lake-id="u7ea06c7f" id="u7ea06c7f">​</span><br></p>
  <p data-lake-id="ueff61ff9" id="ueff61ff9"><span data-lake-id="u25ed7d93" id="u25ed7d93">具体的收集方式也有很多种，可以在客户端进行收集、也可以在统一代理层进行收集、还可以通过redis的自带命令进行收集。redis 4.0.3中提供了redis-cli的热点key发现功能，执行redis-cli时加上–hotkeys选项即可。</span></p>
  <p data-lake-id="ueadb0196" id="ueadb0196"><span data-lake-id="ud9e122f6" id="ud9e122f6" class="lake-fontsize-12" style="color: rgba(25, 26, 31, 0.9)">​</span><br></p>
  <p data-lake-id="uc8b4eea3" id="uc8b4eea3"><span data-lake-id="u34210304" id="u34210304" class="lake-fontsize-12" style="color: rgba(25, 26, 31, 0.9)">​</span><br></p>
  <h2 data-lake-id="IuTOT" id="IuTOT"><span data-lake-id="ua0b5dfd0" id="ua0b5dfd0" style="color: rgba(25, 26, 31, 0.9)">多级缓存</span></h2>
  <p data-lake-id="u2b55e855" id="u2b55e855"><span data-lake-id="u9c766ecd" id="u9c766ecd">解决热key问题最主要的方式就是加缓存。通过缓存的方式尽量减少系统交互，使得用户请求可以提前返回。</span></p>
  <p data-lake-id="u3a0be390" id="u3a0be390"><span data-lake-id="u210bd0f0" id="u210bd0f0">​</span><br></p>
  <p data-lake-id="u87011de5" id="u87011de5"><span data-lake-id="u2d0ecca9" id="u2d0ecca9">这样即能提升用户体验，也能减少系统压力。</span></p>
  <p data-lake-id="uadbaf753" id="uadbaf753"><span data-lake-id="u3cdaa9a1" id="u3cdaa9a1">​</span><br></p>
  <p data-lake-id="uaffcc212" id="uaffcc212"><span data-lake-id="u14a6b8c1" id="u14a6b8c1">缓存的方式有很多，有些数据可以缓存在客户的客户端浏览器中，有些数据可以缓存在距离用户就近的CDN中，有些数据可以通过Redis等这类缓存框架进行缓存，还有些数据可以通过服务器本地缓存进行。</span></p>
  <p data-lake-id="u678b2b1b" id="u678b2b1b"><span data-lake-id="u8f67b421" id="u8f67b421">​</span><br></p>
  <p data-lake-id="ua4fa0ed9" id="ua4fa0ed9"><span data-lake-id="u527abeb2" id="u527abeb2">这种使用多个缓存的情况，就组成了二级缓存、三级缓存等多级缓存了。总之，通过缓存的方式尽量减少用户的的访问链路的长度。</span></p>
  <p data-lake-id="u293c39b0" id="u293c39b0"><span data-lake-id="u9f29fd5b" id="u9f29fd5b">​</span><br></p>
  <p data-lake-id="ua42f3e25" id="ua42f3e25"><span data-lake-id="u970920fb" id="u970920fb">​</span><br></p>
  <h2 data-lake-id="ObeSS" id="ObeSS"><span data-lake-id="ue4de9196" id="ue4de9196">热key备份</span></h2>
  <p data-lake-id="u1281c5d1" id="u1281c5d1"><span data-lake-id="u9a3e21ec" id="u9a3e21ec">有了缓存之后，还会带来一个问题，那就是热点数据如果都被缓存在同一个缓存服务器上，那么这个服务器也可能被打挂。</span></p>
  <p data-lake-id="ufb9747c8" id="ufb9747c8"><span data-lake-id="u8268d95f" id="u8268d95f">​</span><br></p>
  <p data-lake-id="ude97ccf0" id="ude97ccf0"><span data-lake-id="u1a4834a8" id="u1a4834a8">所以，很多人在加了缓存之后， 还可能同时部署多个缓存服务器，如Redis同时部署多个服务器集群。并且实时的将热点数据同步分发到多个缓存服务器集群中，一旦有的集群扛不住了，立刻做切换。</span></p>
  <p data-lake-id="u0576c5d5" id="u0576c5d5"><span data-lake-id="udcfead1c" id="udcfead1c">​</span><br></p>
  <p data-lake-id="u19480678" id="u19480678"><span data-lake-id="u7b696a5b" id="u7b696a5b">单纯的对于Redis热key缓存来说，Redis是有分片机制的，同一个热key可能会都保存在同一个分片中，所以还可以在多个分片中都把热key同步一份，使得查询可以同时从多个分片进行，减少某一个分片的压力。</span></p>
  <p data-lake-id="ue321336b" id="ue321336b"><span data-lake-id="u689cd504" id="u689cd504">​</span><br></p>
  <p data-lake-id="uf10ab113" id="uf10ab113"><span data-lake-id="u0f029dc1" id="u0f029dc1">因为有分片，还有一种情况，就是有可能多个热key都会分到同一个分片中，为了减少这种情况的发生，可以增加更多的分片来分担流量。</span></p>
  <p data-lake-id="ud0859d6d" id="ud0859d6d"><br></p>
  <h2 data-lake-id="YpdiW" id="YpdiW"><span data-lake-id="u358344a3" id="u358344a3">热key拆分</span></h2>
  <p data-lake-id="ud84421ad" id="ud84421ad"><br></p>
  <p data-lake-id="u4db835f3" id="u4db835f3"><span data-lake-id="u505fbbf0" id="u505fbbf0">将一个热key拆分成多个key，在每一个Key后面加一个后缀名，然后把这些key分散到多个实例中。</span></p>
  <p data-lake-id="ua8b9ac3f" id="ua8b9ac3f"><span data-lake-id="ufed388a0" id="ufed388a0">​</span><br></p>
  <p data-lake-id="u303ad92f" id="u303ad92f"><span data-lake-id="u1679d829" id="u1679d829">这样在客户端请求的时候，可以根据一定的规则计算得出一个固定的Key，这样多次请求就会被分散到不同的节点上了。</span></p>
  <p data-lake-id="ued396a75" id="ued396a75"><span data-lake-id="u8f2f7496" id="u8f2f7496">​</span><br></p>
  <p data-lake-id="u7c2fbe22" id="u7c2fbe22"><span data-lake-id="u6455b44c" id="u6455b44c">比如 &lt;淄博烧烤&gt; 是个热点key，</span></p>
  <p data-lake-id="u75749684" id="u75749684"><span data-lake-id="uc20e6c8f" id="uc20e6c8f">​</span><br></p>
  <p data-lake-id="u912dafdb" id="u912dafdb"><span data-lake-id="u46553255" id="u46553255">把他拆分成淄博烧烤_0001、淄博烧烤_0002、淄博烧烤_0003、淄博烧烤_0004，然后把它们分别存储在cluster中的不同节点上，这样用户在查询&lt;淄博烧烤&gt;的时候，先根据用户ID算出一个下标，然后就访问其中一个节点就行了</span></p>
  <p data-lake-id="u0a0a39f5" id="u0a0a39f5"><br></p>
  <p data-lake-id="uebc0de06" id="uebc0de06"><span data-lake-id="u393dfc34" id="u393dfc34">有人问了，这不是意味着一个用户只能拿到部分数据了吗？确实是，但是有时候我们并不一定就需要全部的数据。</span></p>
  <p data-lake-id="ue51be3f1" id="ue51be3f1"><span data-lake-id="ud7ebefb0" id="ud7ebefb0">​</span><br></p>
  <p data-lake-id="udaeaf880" id="udaeaf880"><span data-lake-id="uaa04154d" id="uaa04154d">比如说，同样的两个用户在刷抖音，都想看&lt;淄博烧烤&gt;这个热点相关的视频，但是我们并不一定要给所有用户都推送同样的内容，完全可以把这个词条下面的无数个视频分散存储在不同的节点上，然后给不同的用户推送在不同的节点上的数据就行了。</span></p>
  <p data-lake-id="uf64c0e29" id="uf64c0e29"><span data-lake-id="uf0f42dee" id="uf0f42dee">​</span><br></p>
  <p data-lake-id="u6460dae3" id="u6460dae3"><span data-lake-id="ufb6fa5cb" id="ufb6fa5cb">然后在这个热点key没那么热了之后，再把数据做一下汇总，挑选出一下好的视频在重新推送给没推送到的用户就行了</span></p>
 </body>
</html>